#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <vector>
#include <queue>
#include <memory>
#include <atomic>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <future>
#include <map>
#include <thread>
#include "thread.h"

// 线程池支持模式，  //cached模式，任务处理比较紧急，场景：小而快的任务
enum class PoolMode
{
    FIXED, // 线程池固定数量线程
    CACHED // 线程池线程可动态增长
};

class ThreadPool
{
private:
    // std::vector<Thread*> threads_;  //线程列表  ，有new就要有delete
    // std::vector<std::unique_ptr<Thread>> threads_; // 线程列表  ，有new就要有delete，改用智能指针?
    std::unordered_map<int, std::unique_ptr<Thread>> threads_;
    size_t initThreadSize_;              // 初始的线程数量
    std::atomic_uint currentThreadSize_; // 当前线程数量
    std::atomic_uint idleThreadSize_;    // 空闲线程数量

    using Task = std::function<void()>;
    std::queue<Task> taskQueue_; // 任务队列

    std::atomic_uint taskSize_;        // 任务数量
    int maxThreadSize_;                // 最大线程数量
    int maxTaskSize_;                  // 任务队列最大上限任务数量
    std::mutex taskQueLock_;           // 保证任务队列的线程安全，线程锁(重)
    std::condition_variable notFull_;  // 任务队列不满
    std::condition_variable notEmpty_; // 任务队列不空
    std::condition_variable exitCon_;  // 等待
    PoolMode mode_;                    // 当前线程池的线程模式
    std::atomic_bool isPoolRunning_;   // 线程池运行状态
    void threadFunc(int threadId);     // 解决任务，消费者

    // protected:
    //     friend class Singleton<ThreadPool>; // 线程池单例

public:
    ThreadPool();
    ~ThreadPool();
    void start(int initThreadSize = std::thread::hardware_concurrency()); // 开启线程池
    void setMode(PoolMode mode);                                          // 设置线程池模式
    void setMaxTaskSize(int maxTaskSize);                                 // 设置线程池最大线程数
    bool checkRuningState();                                              // 检查线程池运行状态
    // 给线程池提交任务
    // 使用可变参数模版编程，让submitTask可以接收任意任务函数和任意数量的参数
    // pool.submitTask
    template <typename Func, typename... Args> // 右值引用+引用折叠原理
    auto submitTask(Func &&func, Args &&...args) -> std::future<decltype(func(args...))>
    {
        using RType = decltype(func(args...));
        auto task = std::make_shared<std::packaged_task<RType()>>(
            std::bind(std::forward<Func>(func), std::forward<Args>(args)...));
        std::future<RType> result = task->get_future();
        std::unique_lock<std::mutex> lock(taskQueLock_);
        if (!notFull_.wait_for(lock, std::chrono::seconds(1), [&]() -> bool
                               { return taskSize_ < maxTaskSize_; }))
        {
            auto task = std::make_shared<std::packaged_task<RType()>>(
                []() -> RType
                {
                    return RType();
                });
            (*task)();
            return task->get_future();
        };
        taskQueue_.emplace([task]()
                           { (*task)(); });
        taskSize_++;
        notEmpty_.notify_all();

        if (mode_ == PoolMode::CACHED && taskSize_ > idleThreadSize_ && currentThreadSize_ < maxThreadSize_)
        {
            auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1));
            int threadId = ptr->getThreadId();
            threads_.emplace(threadId, std::move(ptr));
            threads_[threadId]->start();
            idleThreadSize_++;
            currentThreadSize_++;
        }
        return result;
    }
};

#endif // THREADPOOL_H ///:~